EN esta primera parte de la práctica vamos a usar Isomap y LLE para disponer imágenes de personajes conocidos sobre un mapa bidimensional. Lo interesante de este ejercicio es que manejamos puntos de alta dimensionalidad (cada pixel es una característica del punto) y que Isomap y LLE son capaces de extraer los 'grados de libertad de la imagen', entendiendo por éstos las características visuales propias de los objetos representados (perfiles, intensidad luminosa, forma del objeto, poses,...).
Vamos a utilizar la base de datos que python ha incorporado a partir de la base de datos original 'Labeled Faces in the Wild'. Esta es una base de datos de 13000 imágenes de caras de 1680 personas (muchas con 2 o más fotos en ella). Puedes consultar la base de datos original en http://vis-www.cs.umass.edu/lfw/
Las imágenes se representan por su lista de valores de color de sus pixeles, son por tanto, vectores de alta dimensionalidad.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_lfw_people
from sklearn.manifold import Isomap
faces = fetch_lfw_people(min_faces_per_person=30)
print(faces.data.shape)
print(faces.images.shape)
print(faces.target_names)
print(faces.target)
(2370, 2914) (2370, 62, 47) ['Alejandro Toledo' 'Alvaro Uribe' 'Andre Agassi' 'Ariel Sharon' 'Arnold Schwarzenegger' 'Colin Powell' 'David Beckham' 'Donald Rumsfeld' 'George W Bush' 'Gerhard Schroeder' 'Gloria Macapagal Arroyo' 'Guillermo Coria' 'Hans Blix' 'Hugo Chavez' 'Jacques Chirac' 'Jean Chretien' 'Jennifer Capriati' 'John Ashcroft' 'John Negroponte' 'Junichiro Koizumi' 'Kofi Annan' 'Laura Bush' 'Lleyton Hewitt' 'Luiz Inacio Lula da Silva' 'Megawati Sukarnoputri' 'Nestor Kirchner' 'Recep Tayyip Erdogan' 'Roh Moo-hyun' 'Serena Williams' 'Silvio Berlusconi' 'Tom Ridge' 'Tony Blair' 'Vicente Fox' 'Vladimir Putin'] [ 8 4 21 ... 8 10 8]
Vamos a plotear varias imágenes para hacernos una idea del dataset. Las imágenes las hemos transformado a niveles de gris.
# plot some images
fig, ax = plt.subplots(5, 6, subplot_kw=dict(xticks=[], yticks=[]), figsize=(8,8))
for i, axi in enumerate(ax.flat):
_ = axi.imshow(faces.data[i].reshape(62, 47), cmap='gray');
Como se ve de las dimensiones que hemos impreso, hay 2370 imágenes de tamaño 62x47 pixeles = 2914 características (variables) que representan la intensidad de gris.
Vamos a coger un único personaje (George Bush) y vamos a procesarlo con Isomap para hallar las disposiciones de sus fotos en un espacio 2D. Veamos que estructura es capaz de encontrar.
Primero defino una función para poder plotear las imágenes en el plano según sus coordenadas
from matplotlib import offsetbox
# source: https://jakevdp.github.io/PythonDataScienceHandbook/05.10-manifold-learning.html
def plot_components(data, model, images=None, ax=None,
thumb_frac=0.05, cmap='gray'):
ax = ax or plt.gca()
proj = model.fit_transform(data)
ax.plot(proj[:, 0], proj[:, 1], '.k')
if images is not None:
min_dist_2 = (thumb_frac * max(proj.max(0) - proj.min(0))) ** 2
shown_images = np.array([2 * proj.max(0)])
for i in range(data.shape[0]):
dist = np.sum((proj[i] - shown_images) ** 2, 1)
if np.min(dist) < min_dist_2:
# don't show points that are too close
continue
shown_images = np.vstack([shown_images, proj[i]])
imagebox = offsetbox.AnnotationBbox(
offsetbox.OffsetImage(images[i], cmap=cmap),
proj[i])
ax.add_artist(imagebox)
Actividad 1: Parte 1: Explica en este contexto el uso de Isomap respondiendo a estas preguntas: +a) ¿Con qué valores calculamos la distancia entre dos elementos, es decir, qué son las características de los datos?
La características de los datos son el nivel de gris que tiene cada píxel de la imagen (2914 cracaterísticas).
+b)¿Qué significa que dos imágenes están cerca?
Significa que comparten similitudes estructurales en el conjunto de datos original, es decir, las imagenes son similares, y esa similitud se conserva en la representación reducida de Isomap.
+c)¿Vamos a conocer en algún momento qué forma o expresión matemática tiene la supuesta variedad donde están alojadas las imágenes? ¿Conocemos su dimensión intrínseca?
No necesariamente hace falta conocer la expresión matemática. Isomap no requiere conocer explícitamente la forma o expresión matemática de la variedad subyacente. En lugar de eso, se basa en la estructura de vecindad para aproximar la distancia geodésica entre puntos en la variedad.
Isomap busca determinar la dimensión intrínseca de una variedad al encontrar una representación de baja dimensión que capture las relaciones geodésicas entre los puntos en dicha variedad. La dimensión intrínseca se obtiene a partir del número de componentes principales retenidos en el proceso de reducción de dimensionalidad.
+d)¿Contienen los puntos hallados en el espacio embebido parte de la información original (intensidad de grises)? ¿Qué son esos puntos según la teoría en que se basa Isomap?
Los puntos en el espacio resultante son básicamente una versión comprimida de la información original de las imágenes, especialmente las tonalidades de grises. La idea es que esta representación en un espacio más pequeño mantiene las relaciones especiales entre los puntos originales. Al conservar estas relaciones, obtenemos una representación que guarda las características importantes de las imágenes y las complicadas conexiones entre los datos.
Parte 2 Ahora calculamos Isomap y disponemos las imagenes. Debes llamar a la función plot_components con el modelo de Isomap con sus parámetros n_components=2 y n_neighbors=?? Haz algunas pruebas con el número de vecinos para quedarte con la mejor. El concepto de mejor consiste en que las fotos se distribuyen sobre el plano, agrupadas por algunas características intrísecas de la imagen.
Escribe en una caja a continuación qué pruebas has hecho y qué disposición de las fotos tiene la que has elegido como mejor.
from sklearn.manifold import Isomap
np.random.seed(8888)
fig, ax = plt.subplots(figsize=(10, 10))
#El target de Bush es el número de índice del vector de nombres que se ha impreso antes
data = faces.data[faces.target==8]
images = faces.images[faces.target==8]
nombre=faces.target_names[8]
print(nombre)
#Haz la llamada con el modelo correcto de Isomap
plot_components(data, model= Isomap(n_neighbors= 50, n_components = 2), images=images, thumb_frac=0.1)
George W Bush
El numero de k-vecinos determina cuantas coenxiones existen entre los puntos en el grafo. Un valor bajo de k-vecinos nos dará grafos más dispersos, en cambio, un valor de k-vecinos alto nos dará un grafo denso.
Tambien debemos tener en cuanta que generalmente un valor alto de k-vecinos resulta una mejor distancia geodésica.
En el caso de las imagenes si usamos un número de k-vecinos pequeño no observamos una estructura clara entre todas las imágenes pero estas se agrupan entre regiones de similitud, por el contrerio, si aumentamos el número no obervamos estos grupos pero vemos una tendencia clara en el global de las imágenes. En nuestro caso las vemos como en el eje y las imágenes van de más claras a más oscuras.
Actividad 2: Experimenta con al menos dos personajes más. Configura el sistema para algún personaje del cual tengamos en la base de datos al menos 50 fotografías (encuentra el parámetro en el código).
Indica cuáles son a tu parecer las características intrínsecas que se están proyectando con las nuevas caras. Escríbelo en una caja a continuación.
# Vemos que personajes tienen más de 50 imagenes
indice, num = np.unique(faces.target, return_counts=True)
personas_50 = indice[num >= 50]
for i in personas_50:
indice = np.where(faces.target == i)
indice = indice[0][0]
print(faces.target_names[i], 'imagen:', i)
Ariel Sharon imagen: 3 Colin Powell imagen: 5 Donald Rumsfeld imagen: 7 George W Bush imagen: 8 Gerhard Schroeder imagen: 9 Hugo Chavez imagen: 13 Jacques Chirac imagen: 14 Jean Chretien imagen: 15 John Ashcroft imagen: 17 Junichiro Koizumi imagen: 19 Serena Williams imagen: 28 Tony Blair imagen: 31
from sklearn.manifold import Isomap
np.random.seed(8888)
fig, ax = plt.subplots(figsize=(10, 10))
#El target de Bush es el número de índice del vector de nombres que se ha impreso antes
data = faces.data[faces.target==31]
images = faces.images[faces.target==31]
nombre=faces.target_names[31]
print(nombre)
#Haz la llamada con el modelo correcto de Isomap
plot_components(data, model= Isomap(n_neighbors= 50, n_components = 2), images=images, thumb_frac=0.1)
Tony Blair
from sklearn.manifold import Isomap
np.random.seed(8888)
fig, ax = plt.subplots(figsize=(10, 10))
#El target de Bush es el número de índice del vector de nombres que se ha impreso antes
data = faces.data[faces.target==19]
images = faces.images[faces.target==19]
nombre=faces.target_names[19]
print(nombre)
#Haz la llamada con el modelo correcto de Isomap
plot_components(data, model= Isomap(n_neighbors= 30, n_components = 2), images=images, thumb_frac=0.1)
Junichiro Koizumi
from sklearn.manifold import Isomap
np.random.seed(8888)
fig, ax = plt.subplots(figsize=(10, 10))
#El target de Bush es el número de índice del vector de nombres que se ha impreso antes
data = faces.data[faces.target==7]
images = faces.images[faces.target==7]
nombre=faces.target_names[7]
print(nombre)
#Haz la llamada con el modelo correcto de Isomap
plot_components(data, model= Isomap(n_neighbors= 50, n_components = 2), images=images, thumb_frac=0.1)
Donald Rumsfeld
Isomap se enfoca en resaltar los bordes y contornos importantes, como las líneas y formas que definen la imagen. También presta atención a cómo cambian las intensidades de color, capturando la luz y sombra. Además, busca patrones y estructuras visuales, como formas repetitivas o detalles distintivos. Así, obtienes una representación en dos dimensiones que conserva estas características visuales clave de tus imágenes.
También en ciertos problemas de imágenes, Isomap descubre características intrínsecas de las imágenes que están relacionadas con las formas de los objetos que representan y permiten agruparse a éstos por su apariencia visual (cosa no trivial ya que una imágen en la forma en que la procesamos en Isomap no es mas que un conjunto de pixeles sin coherencia visual entre ellos en principio).
Para hacer esta parte, debes bajarte una base de datos de fotos de objetos de la Universidad de Columbia (EE.UU.) que puedes encontrar en https://www1.cs.columbia.edu/CAVE/software/softlib/coil-100.php.
Modifica los caminos de las instrucciones de abajo para cargar la base de datos de imágenes.
Nota Importante Cuando descargues la base de datos de objetos en tu ordenador, hay dos ficheros que no tienen extensión 'png' (no son imagenes). Debes eliminarlos de la carga de imágenes o te dará error.
import os
import matplotlib.image as img
from skimage.color import rgb2gray
os.getcwd()
def get_sample(path):
ix = [int(i) for i in np.arange(0, len(os.listdir(path)), 72)]
object_files = [os.listdir(path)[i] for i in (ix)]
data = []
for file in object_files:
data.append(rgb2gray(plt.imread(path + '\\' + file)))
data = np.array(data)
images = data
data = data.reshape(100, 128*128)
return data, images
path = r'C:\Users\ampar\Documents\uni\TERCERO\primer_cuatri\AGRUPAMIENTO\PRACTICAS\P6\Base_datos_objetos_Univ_Columbia\coil-100\coil-100'
sample_data, sample_images = get_sample(path)
sample_data.shape
sample_images.shape
(100, 128, 128)
Vamos a hora a aplicar Isomap al conjunto de imágenes y vamos a seleccionar unas cuantas para visualizarlas en la proyección que ha obtenido Isomap.
#Creditos: Drew Wilimitis
from sklearn.manifold import Isomap
plt.style.use('seaborn-poster')
fig, ax = plt.subplots(figsize=(14, 11))
#Introduce en número de dimensiones de salida a 2
plot_components(sample_data,
model=Isomap(n_components=2),
images=sample_images[:, ::2, ::2],
thumb_frac=0.07)
Actividad 3: Indica si Isomap es capaz de captar algunas estructuras de las imagenes y cuáles te parece que son.
Insertemos ahora un nuevo código capaz de seleccionar imagenes de la base de datos para centrarnos en unos pocos objetos:
La observación de que en el eje X se percibe una transición desde estructuras más anchas a más estrechas, mientras que en el eje Y se experimenta una transición desde estructuras más estrechas a más anchas.
# read in all the images for a collection of objects
def get_objects(path, keys):
obj_keys = ['obj' + str(key) + '__' for key in keys]
data = []
for obj_key in obj_keys:
object_files = [x for x in os.listdir(path) if obj_key in x]
for image in object_files:
data.append(rgb2gray(plt.imread(path + '/' + image)))
data = np.array(data)
images = data
data = data.reshape(len(keys)*72, 128*128)
return data, images
# select a set of indices for object images
objects = np.arange(1, 90, 15)
object_data, object_images = get_objects(path, objects)
object_data.shape
object_images.shape
(432, 128, 128)
Hemos seleccionado imágenes de objetos con varias formas muy distintas. Vamos a visualizarlos ejecutando el código de abajo:
fig, ax = plt.subplots(4, 4, subplot_kw=dict(xticks=[], yticks=[]), figsize=(8,8))
for i, axi in enumerate(ax.flat):
_ = axi.imshow(object_images[(i+1)*24 - 4], cmap='gray');
Actividad 4: Vamos a aplicar Isomap a dicho dataset. Estudia la configuración del hiperparámetro del algoritmo, para ello prueba con valores en diferentes rangos.
Explica tus resultados en una caja a continuación.
fig, ax = plt.subplots(figsize=(10, 10))
plot_components(object_data,
model=Isomap(n_components=2, n_neighbors= 15),
images=object_images[:, ::2, ::2],
thumb_frac=0.1)
Actividad 5 ¿Consigue Isomap agrupar las imágenes en las clases de formas correctas?. ¿Que grados de libertad encuentra en cada eje?
Con un número de k-vecino bajo Isomap consigue agrupar los objetos dependiendo de su clase, tanto los tres tipos de caja como los coches y las tazas se agrupan en regiones del espacio distinguibles.
Actividad 6 Prueba lo anterior con otro grupo de imágenes. Describe las pruebas y los resultados en una caja a continuación.
Vamos a probar el algoritmo LLE con el banco de caras anterior y, específicamente . con la caras de George W. Bush.
Debes importar ahora el algoritmo LLE. Búscalo en scikit. Este algoritmo lo llamará la función anterior que ya conocemos plot_components().
Actividad 7: Debes preprarar el modelo, igual que Isomap, con los parámetros n_components para dos dimensiones y n_neighbors=?? . Vuelve a hacer pruebas para ver con que valores de construcción de la localidad te sale mejor. Describe los resultados a continuación
from sklearn.manifold import LocallyLinearEmbedding
np.random.seed(8888)
fig, ax = plt.subplots(figsize=(10, 10))
data = faces.data[faces.target==8]
images = faces.images[faces.target==8]
nombre=faces.target_names[8]
#Introduce/estudia los par´metros de lle aquí
lle = LocallyLinearEmbedding(n_neighbors = 20, n_components=2)
print(nombre)
plot_components(data, model=lle, images=images, thumb_frac=0.1)
George W Bush
Actividad 8 Repara en que es lo que estamos haciendo con LLE. +a) ¿Qué dimensiones iniciales tiene cada vector que representa una imagen?. ¿Dónde se proyectan en la salida, es decir, con cuantas dimensiones?
En el contexto de LLE, inicialmente, cada vector que representa una imagen tiene dimensiones equivalentes al número de píxeles en dicha imagen. Cuando aplicamos LLE y proyectamos estas representaciones en la salida, determinamos el número deseado de dimensiones mediante el parámetro 'n_components'. En este caso, al establecer 'n_components' en 2, estamos proyectando las imágenes en un espacio de dos dimensiones. Así, cada imagen se representa en este nuevo espacio con solo dos dimensiones después de aplicar el algoritmo LLE.
+b) ¿Qué diferencia hay en la organización de los puntos embebidos usando LLE respecto a la que hace Isomap?
La diferencia principal en la organización de puntos embebidos entre Isomap y LLE reside en la manera en que preservan la estructura de vecindad en el espacio de salida. Mientras que Isomap se enfoca en conservar las distancias geodésicas entre puntos para reflejar la proximidad original, LLE prioriza la preservación de relaciones lineales locales entre puntos y sus vecinos más cercanos. En resumen, Isomap se orienta hacia la conservación de distancias geodésicas, mientras que LLE se centra en mantener relaciones lineales locales, dando como resultado organizaciones espaciales distintas en el espacio de salida.
+c) Compara las proyecciones de los puntos en el espacio 2d de Isomap con las obtenidas con LLE. ¿Qué parecidos/diferencias encuentras? ¿Las dos proyectan en los dos ejes (abcisas/ordenadas) los mismos grados de libertad (ej. luminosidad,perfil, arriba/abajo, ojos abirtos/cerrados, boca abierta/cerrada)?
Las proyecciones en el espacio 2D a través de Isomap y LLE comparten similitudes al conservar características visuales como luminosidad, perfil facial y posición en la imagen. A pesar de estas similitudes, se destacan diferencias clave en la manera en que modelan las relaciones locales entre puntos: LLE se concentra en preservar relaciones lineales locales, mientras que Isomap da prioridad a la preservación de distancias geodésicas.
Es probable que ambas metodologías proyecten en ambos ejes (abcisas/ordenadas) grados de libertad similares, como la posición arriba/abajo en la imagen. No obstante, podrían existir variaciones específicas debido a sus enfoques distintos.
Actividad 9 La implementación de LLE de python proporciona también como dato el error de reconstrucción. Ejecuta el algoritmo LLE en un bucle para vecindades k desde 3 a 20 y guárdate en un vector los errores de reconstrucción para dichas ejecuciones. Representa en una gráfica los errores de reconstrucción donde en abcisas esté el número de iteración. Justifica la tendencia creciente o decreciente de la gráfica que te sale.
faces = fetch_lfw_people(min_faces_per_person=30)
data = faces.data[faces.target == 8]
errors = []
neighbors_range = range(3, 21)
for n_neighbors in neighbors_range:
lle = LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=2)
lle.fit(data)
reconstruction_error = lle.reconstruction_error_
errors.append(reconstruction_error)
plt.plot(neighbors_range, errors, marker='o')
plt.title('Error de Reconstrucción de LLE en función de Vecindades')
plt.xlabel('Número de Vecindades')
plt.ylabel('Error de Reconstrucción')
plt.show()
La tendencia creciente se debe a que a medida que aumenta k, el modelo tiene en cuenta más vecinos al realizar la reconstrucción local, lo que podría llevar a una mayor complejidad en la representación.
Vamos a aplicar LLE a una variedad sintética algo compleja para ver cómo es capaz de recoger su estructura no lineal y proyectarla en 2D.
Generamos una superficie en forma de 'silla de montar' con dos picos.
plt.style.use('default')
n = 5000
param = 1
xy = 1 - 2 * np.random.rand(2, n)
p = np.array([xy[1, :], xy[0, :], param * np.sin(np.pi * xy[0, :]) * np.tanh(3 * xy[1, :])]).T
color = p[:, 2]
fig = plt.figure(figsize = (9, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(p[:, 0], p[:, 1], p[:, 2], c=color, cmap=plt.cm.jet)
plt.title('"Twin Peaks" Dataset', size=12)
ax.view_init(20, -19);
Actividad 10 Aplica a este dataset el algoritmo LLE. Proyéctalo a un espacio de dos dimensiones y haz un estudio para el hiperparámetro del número de vecinos que constituye una localidad de cada punto, indicando los resultados que has obtenido para cada valor en términos de la organización en el plano de los datos embebidos (si se agrupan los datos que inicialmente estaban juntos en la variedad) y de su error de reconstrucción. Escribe los resultados en una caja a continuación.
from sklearn.manifold import LocallyLinearEmbedding
from sklearn.metrics import mean_squared_error
n_neighbors_values = [5, 10, 15, 20, 25, 30]
for n_neighbors in n_neighbors_values:
# Aplicar LLE con el número de vecinos especificado
lle = LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=2)
X_reduced = lle.fit_transform(p)
# Visualizar los resultados en 2D
fig = plt.figure(figsize = (5, 5))
plt.title(f'LLE with k = {n_neighbors}', size=12)
plt.scatter(X_reduced[:,0], X_reduced[:,1], c=color, cmap=plt.cm.jet)
plt.show()
Actividad 11 ¿Cuál es el número de vecinos que te proporciona un mejor LLE?
Explica a continuación la diferencia entre el concepto de 'número de vecinos' en ISOMAP y en LLE.
Para el conjunto de datos que estamos trabajando el número de vecinos que proporciona un mejor LLE es a partir de n_neighbors = 15
SOMAP: El número de vecinos se refiere a la cantidad de vecinos más cercanos considerados al construir el grafo de vecindad. Este grafo se utiliza para aproximar las distancias geodésicas entre puntos en el espacio de datos original, centrándose en capturar las distancias a lo largo de la variedad subyacente y preservar la estructura global.
LLE: El valor de 'número de vecinos' se usa en dos etapas distintas. En la primera etapa, se seleccionan los vecinos más cercanos para cada punto en el espacio de datos original, utilizándolos para aproximar las relaciones lineales locales. En la segunda etapa, se eligen vecinos cercanos en el espacio de menor dimensión para cada punto en el espacio reducido, empleándolos para reconstruir el punto en el espacio original. LLE se centra en preservar relaciones lineales locales en ambas etapas del proceso.
Otra de las aplicaciones en las que se usan tanto Isomap como LLE es en el tracking de imágenes. El tracking consiste en ordenar una serie de imágenes de tal manera que represente una secuencia. Lo más habitual es que las imágenes representen algún objeto o ser vivo en movimiento y el sistema de tracking las ordene en una secuencia de seguimiento del objeto.
Vamos a crear nuestra propia secuencia superponiendo a una imágen de ruido blanco (que se supone que hace de fondo neutro) las imágenes en distintas posiciones de un barco. El objetivo es que LLE encuentre ese patrón de desplazamiento y ordene los grupos de imágenes por posiciones similares.
Carga la imagen 'barco.png' que se te proporciona. Primero la vamos a convertir a grises y la vamos a reducir de resolución para que nos quepa en el fondo de ruido.
import cv2
import matplotlib.image as img
from skimage.color import rgb2gray
plt.style.use('default')
# read in the image
image = cv2.imread(r"C:\Users\ampar\Documents\uni\TERCERO\primer_cuatri\AGRUPAMIENTO\PRACTICAS\P6\barco.png")
# convert to gray and resize
print(image.shape)
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
#image = object_images[153]
res = cv2.resize(image, dsize=(32, 32), interpolation=cv2.INTER_CUBIC)
plt.subplot(121)
plt.title('Original 128x128')
plt.imshow(image,cmap='gray')
plt.subplot(122)
plt.title('Resized 32x32')
plt.imshow(res,cmap='gray')
plt.show();
(128, 128, 3)
Vamos a crear ahora una imagen de 64x64 pixels de ruido blanco. Para ello carga en un array llamado test_img 64x64 valores aleatorios entre 0 y 255
# create image with random noise
test_img = np.random.randint(0, 256, size=(64, 64), dtype=np.uint8)
plt.imshow(test_img);
Actividad 12 Ahora vamos a crear la secuencia de imagenes sobre fondo de ruido. Almacenaremos la secuencia en la lista 'images'. Vamos a ir moviendo el barco para cada una de las 64/2 filas del fondo, en cada una de sus 64/2 columnas (para que quepa la imagen completa).
Deberia quedarte algo como esto:
# iterate and create shifted images
images = []
for i in range(33):
for j in range(33):
tmp = np.copy(test_img)
# desliza el barco a lo largo del fondo durante 32 columnas para cada fila (de las primeras 32)
#piensa cómo debes configurar los rangos de los índices para poner el barco
row_range = slice(i, i + res.shape[0])
col_range = slice(j, j + res.shape[1])
tmp[row_range, col_range] = res
images.append(tmp);
Ahora vamos a visualizar el resultado:
plt.imshow(res,cmap='gray')
# plot some of the generated images
F = plt.figure(figsize=(15,10))
G = plt.GridSpec(3, 4, left=.01, right=.99, bottom=0.05, top=0.9, wspace=.01,
hspace=0.05, figure=F)
ax = plt.subplot(G[0])
_ = ax.imshow(images[0], cmap='gray')
selected_images = [0, 12, 24, 32, 430, 438, 446, 461, 1056, 1064, 1078, 1088]
ax.set_axis_off()
ax.set_aspect('equal')
for i in range(1, 12):
ax = plt.subplot(G[i])
_ = ax.imshow(images[selected_images[i]], cmap='gray')
ax.set_axis_off()
ax.set_aspect('equal');
Utiliza el codigo siguiente para llamar a LLE y luego visualizar la proyección 2D que obtenemos.
X = np.array(images).reshape(1089, 4096)
#Pon en esta variable el número de vecinos para la reconstrucción
k=20
lle = LocallyLinearEmbedding(n_neighbors=k, n_components=2)
X_reduced = lle.fit_transform(X)
fig = plt.figure(figsize = (8, 8))
plt.scatter(X_reduced[:, 0], X_reduced[:, 1])
plt.title('LLE with k = '+str(k), size=12);
Actividad 13 Sin visualizar todavia la correspondencia de los puntos obtenidos con las imágenes originales: ¿Qué puedes decir del dataset observando la disposición de los puntos en el espacio bidimensional? Responde a continuación
Las imágenes con ubicaciones similares (derecha, izquierda, centro, arriba o abajo) están agrupadas, destacan patrones espaciales que sugieren la existencia de características comunes en esas regiones.
Vamos ahora a superponer a la proyección algunas de las imágenes correspondientes.
def plot_components(data, model, images=None, ax=None,
thumb_frac=0.05, cmap='gray'):
ax = ax or plt.gca()
proj = model.fit_transform(data)
ax.plot(proj[:, 0], proj[:, 1], '.k')
if images is not None:
min_dist_2 = (thumb_frac * max(proj.max(0) - proj.min(0))) ** 2
shown_images = np.array([2 * proj.max(0)])
for i in range(data.shape[0]):
dist = np.sum((proj[i] - shown_images) ** 2, 1)
if np.min(dist) < min_dist_2:
# don't show points that are too close
continue
shown_images = np.vstack([shown_images, proj[i]])
imagebox = offsetbox.AnnotationBbox(
offsetbox.OffsetImage(images[i], cmap=cmap, zoom=1),
proj[i])
ax.add_artist(imagebox)
for i in selected_images:
imagebox = offsetbox.AnnotationBbox(
offsetbox.OffsetImage(images[i], cmap='gray'),
proj[i])
ax.add_artist(imagebox)
plt.figure(figsize=(8,8))
plot_components(X,
model=LocallyLinearEmbedding(n_components=2, n_neighbors=k),
thumb_frac=0.3,
images=images);
Actividad 14: ¿Qué grados de libertad de las imágenes originales ha reproducido en el el espacio bidimensional el algoritmo LLE?
En el espacio bidimensional, el algoritmo LLE ha capturado y reflejado las relaciones locales entre las imágenes, lo que equivale a reproducir los diversos grados de libertad presentes en las imágenes originales. La agrupación de imágenes con características similares en regiones específicas de la proyección indica que el algoritmo ha logrado representar variaciones en la orientación, posición, iluminación y otras características específicas de las imágenes originales.